/**
 * CQL 的语法规则
 */
grammar CQL;
@lexer::header {
	package org.zhadoop.stream.cql.semanticanalyzer.parser;
}

@parser::header{
 	package org.zhadoop.stream.cql.semanticanalyzer.parser;
 }
 
 statement
 	:	ddlStatement EOF
 	| 	execStatement EOF
 	;
 	
execStatement
	: insertStatement
	| selectStatement
	;
	
 ddlStatement
 	: createInputStreamStatement
 	| createOutputStreamStatement
 	| submitApplication
 	;
 
 /*
  * CQL 中的select 语句定义
  */	
 insertStatement
 	: insertClause selectStatement
 	;
 	
insertClause
	: KW_INSERT KW_INTO KW_STREAM? streamName
	;

selectStatement
	: selectClause 
	  fromClause 
	  whereClause?
	  groupByClause?
	  havingClause?
	  orderByClause?
	  limitClause? 
	  parallelClause?
	;

selectClause
	: KW_SELECT subSelectClause
	;

fromClause
	: KW_FROM joinSource combineCondition?
	;
	
whereClause
	: KW_WHERE searchCondition
	;
	
searchCondition
	: expression
	;


groupByClause
	: KW_GROUP KW_BY groupByList
	;
	
groupByList
	:   groupByExpression (COMMA groupByExpression )*
	;
	
groupByExpression
	: expression;


havingClause
	: KW_HAVING havingCondition;
	
havingCondition
	: expression
	;

orderByClause
	: KW_ORDER KW_BY columnNameOrderList
	;
	
columnNameOrderList
	: columnNameOrder (COMMA columnNameOrder)* 
	;
	
columnNameOrder
	: expression columnOrder?
	;
	
columnOrder
	:	KW_ASC
	|	KW_DESC
	;

limitClause
	: KW_LIMIT limitRow
	;
	
limitRow
	: constIntegerValue
	;

combineCondition
	: KW_COMBINE LPAREN expression (COMMA expression)+ RPAREN;

subSelectClause
	: distinct? selectList
	;
	
distinct
	: KW_DISTINCT
	;

selectList
	: selectItem (COMMA selectItem)*;
	
selectItem
	: selectExpression
	;

selectExpression
	: expression selectAlias?
	| streamAllColumns
	;

selectAlias
	:	multialias
	|	singleAlias
	;
	
multialias
	:	KW_AS LPAREN columnALias (COMMA columnALias)* RPAREN
	;

singleAlias
	:	KW_AS? columnALias
	;

	
streamAllColumns
	: (streamName DOT)? STAR
	;
	
/*
 * a join b join c 应该先处理 b join c
 */
joinSource
	: fromSource joinRigthBody*
	;
	
joinRigthBody
	: joinToken fromSource onCondition?
	;


onCondition
	: KW_ON expression
	;

fromSource
	:	streamBody
    |	datasourceBody
    ;
   
/**
 * 数据源的别名是可选的，
 * 也就是说可以使用dataSourceName.columnName
 * 也可以使用sourceAlias.columnName
 */
datasourceBody
	:	KW_DATASOURCE dataSourceName datasourceArguments sourceAlias?
	;
	
datasourceArguments	
	:	LSQUARE 
		datasourceSchema
		COMMA
		datasourceQuery
		RSQUARE
	;
	
/**
	数据源查询语句，所有的CQL参数都在这个query中定义
*/    
datasourceQuery
	:	KW_QUERY LPAREN datasourceQueryArguments? RPAREN
	;

/**
	数据源查询参数，
*/    	
datasourceQueryArguments
	:	expression (COMMA expression)*
	; 

/**
 * 数据源中使用到的schema
 */
datasourceSchema
	: KW_SCHEMA LPAREN columnNameTypeList RPAREN
	;
 
joinToken
	 :	innerJoin
    |	leftJoin
    |	rightJoin
    |	fullJoin
    |	crossJoin
    |	naturalJoin       		
    ;
    
naturalJoin
	:	KW_NATURAL KW_JOIN
	;
   
crossJoin
	:	COMMA
	|   KW_CROSS KW_JOIN
	;	
 
fullJoin
	:	KW_FULL (KW_OUTER)? KW_JOIN
	;

rightJoin
	:	KW_RIGHT (KW_OUTER)? KW_JOIN
	;

    
leftJoin
	: KW_LEFT (KW_OUTER)? KW_JOIN 
	;

    
innerJoin
	: KW_JOIN
	| KW_INNER KW_JOIN
	;
	
subQuerySource
	: LPAREN selectStatement RPAREN;


streamBody
	: streamSource sourceAlias?unidirection?
	;
	
unidirection
	: KW_UNIDIRECTION
	;

sourceAlias
	:	KW_AS? streamAlias
	;

	
streamSource
	: streamName
	| subQuerySource
	;
	
 
 /*
 *	CQL中的输入流输出流定义
 */
createInputStreamStatement
 	: 	KW_CREATE KW_INPUT KW_STREAM streamName
 		(LPAREN columnNameTypeList RPAREN)?
 		comment?
 		serdeDefine?
 		sourceDefine
 		parallelClause?
 	;
 	
createOutputStreamStatement
	: KW_CREATE KW_OUTPUT KW_STREAM streamName
	  (LPAREN columnNameTypeList RPAREN)?
	  comment?
	  serdeDefine?
	  sinkDefine
	  parallelClause?
	  ;
	
columnNameTypeList
	: columnNameType (COMMA columnNameType)*
	;
		  
serdeDefine
	 :   serdeClass
     	 serdeProperties?
    ;
serdeClass
    :	KW_SERDE className
    ;

serdeProperties
    :	streamProperties
    ;
    
sourceDefine
	:   sourceClause
    sourceProperties?
	;

sourceClause
    :	KW_SOURCE className
    ;   

sourceProperties
    :	streamProperties
    ; 

sinkDefine
	: sinkClause
	  sinkProperties?
	;
	
sinkClause
	: KW_SINK className
	;
	
sinkProperties
	: streamProperties 
	;
 	
parallelClause
   :	KW_PARALLEL constIntegerValue
   ;

primitiveType
		:	KW_INT
		|	KW_LONG
		|	KW_BOOLEAN
		|	KW_FLOAT 
    	|	KW_DOUBLE
    	|	KW_STRING
    	|	KW_TIMESTAMP
    	|	KW_DATE
    	|	KW_TIME
    	|	KW_DECIMAL	
		;	
	
colType
    	:	primitiveType
    	;		

columnNameType
		: columnName colType comment? 
		;
		
comment
		: KW_COMMENT commentString
		;

commentString
		: StringLiteral 
		;
		
streamPropertiesList
    :	keyValueProperty (COMMA keyValueProperty)*
    ;
    
keyValueProperty
    :	confName EQUAL confValue
    ;

/*
 * 表达式语法定义
 * CQL 的各种运算符
 * 算术运算符：+，-，*，/,%,DIV（取余）
 * 关系运算符:>,<,>=,<=,=,!=,<>
 * 逻辑表达符：And、Or、Not
 * 位运算符:按位与(&),按位或(|)，按位非(~)，按位异或（^)
 * 连接运算符:'+'
 * 
 * CQL运算符优先级从高到低：
 * cast,case,when
 * 表达式语法定义
CQL的各种运算符
算术运算符:+,-,*,/,%,DIV(取余)
关系运算符:>,<,>=,<=,=,!=,<>
逻辑运算符：And,Or,Not
位运算符：按位与(&)，按位或(|)，按位非(~)，按位异或(^)
连接运算符： '+'

CQL运算符优先级从高到低：
cast,case,when,
一元运算符(+,-,^) (正负)
算术运算符(*,/,DIV(取余))
算术运算符(+,-)
连接运算符（'||'）
位运算符(&,|,~,^)
关系运算符（=, !=, <, >, <=, >=,<>）
IS [NOT] NULL, LIKE, [NOT] BETWEEN,[NOT] IN, EXISTS,
not
and
or

说明：
1、可以使用括号改变优先级顺序,括号内的运算先执行
2、可以看出OR的优先级最低，算术运算符的优先级最高,原子类型的表达式和常量优先计算
3、乘除的优先级高于加减;
4、同一优先级运算符从左向右执行
 * 
 */
expression
	: logicExpressionOr
	;
	
logicExpressionOr
	: logicExpressionAnd (KW_OR logicExpressionAnd)*
	;
	
logicExpressionAnd
	: logicExpressionNot (KW_AND logicExpressionNot) ;
	
logicExpressionNot
	: identifierNot? equalRelationExpression
	;

equalRelationExpression
	:  isNullLikeInExpressions
	|  expressionExists
	;

expressionExists
	: KW_EXISTS subQueryExpression;
	
isNullLikeInExpressions
	: binaryExpression
	 (KW_IS nullCondition
		|	expressionLike
		|	expressionBetween
	    |	expressionIn
	    )?
	 ;

binaryExpression
	: bitExpression relationExpression* ;

expressionLike
	: identifierNot? precedenceEqualNegatableOperator bitExpression;
	
precedenceEqualNegatableOperator
	: KW_LIKE
	| KW_RLIKE
	| KW_REGEXP
	;

expressionBetween
	: identifierNot? KW_BETWEEN expressionBetweenMinValue KW_AND expressionBetweenMaxValue
	;
expressionBetweenMaxValue
	: bitExpression
	;

expressionBetweenMinValue
	: bitExpression
	;

expressionIn
	: identifierNot? KW_IN expressions;
	
expressions
	: LPAREN expression (COMMA expression)* RPAREN
	;
	
subQueryExpression
	: LPAREN selectStatement RPAREN;

relationExpression
	: relationOperator bitExpression
	;
	
relationOperator
	: EQUAL
	| EQUAL_NS
	| NOTEQUAL
	| LESSTHANOREQUALTO
	| LESSTHANOREQUALTO
	| LESSTHAN
	| GREATERTHANOREQUALTO
	| GREATERTHAN;


bitExpression
	: arithmeticPlusMinusExpression (bitOperator arithmeticPlusMinusExpression)*;
	
bitOperator
 	: BITWISEOR
	| AMPERSAND
	| BITWISEXOR
	;

arithmeticPlusMinusExpression
	: arithmeticStarExpression (arithmeticPlusOperator arithmeticStarExpression)*
	;

arithmeticPlusOperator
	: PLUS
	| MINUS
	| CONCATENATION
	;
	
arithmeticStarExpression
	: fieldExpression (arithmeticStarOperator fieldExpression)*
	;

arithmeticStarOperator
	:  STAR
	| DIVIDE
	| MOD
	| DIV
	;
	
fieldExpression
	: (streamNameOrAlias DOT)? atomExpression
	;
	
atomExpression
	:	constNull
    |	constant
    |	expressionPrevious
    |	function
    |	castExpression
    |	caseExpression
    | 	whenExpression
    |	columnName
    | 	expressionWithLaparen
    ;
    
expressionWithLaparen
	:  LPAREN expression RPAREN
	;

whenExpression
	: KW_CASE	(caseWhenBodyWhenBody caseWhenBodyThenBody)+ caseWhenElse? KW_END
	;

caseExpression
	:	KW_CASE caseHeadExpression (caseWhenBodyWhenBody caseWhenBodyThenBody)+ caseWhenElse? KW_END 
    ;
    
caseWhenElse
	: KW_ELSE expression
	;

caseWhenBodyThenBody
	: KW_THEN expression
	;

caseWhenBodyWhenBody
	: KW_WHEN expression
	;

caseHeadExpression
	: expression
	;


castExpression
	:	KW_CAST LPAREN expression KW_AS  primitiveType RPAREN
    ;

function
	: functionName LPAREN distinct? (selectExpression (COMMA selectExpression)*)?  RPAREN 
	;

expressionPrevious
	: KW_PREVIOUS expression
	;

    
constant
	: unaryOperator?
	    (
	    	constIntegerValue
	    |	constLongValue
	    |	constFloatValue
	    |	constDoubleValue
	    |	constBigDecimalValue
	    )
    |	constStingValue
    |	booleanValue
    ;
    
booleanValue
    :	KW_TRUE 
    |	KW_FALSE
    ;
    

constStingValue
	: StringLiteral
	;

    
constIntegerValue
	:	IntegerNumber
	;

constBigDecimalValue
	: DecimalLiteral
	;

constDoubleValue
	: DoubleLiteral
	;

constFloatValue
	: FloatLiteral
	;

constLongValue
	: LongLiteral
	;
	
/*
 * CQL中的命令定义
 */
 submitApplication
 	:	KW_SUBMIT KW_APPLICATION isForce? applicationName? path?
 	;

/*
 * Identifiers
 */
 /*
 * 由于担心语法冲突或者 其他导致别名失效等原因，
 * 暂时只修改函数名称相关，即只修改函数名称中包含的
 * 这些关键字。
 * KW_UNIDIRECTION
 */
 cqlIdentifier
 	: KW_DAY
 	| KW_HOUR
 	| KW_MINUTES
 	| KW_SECONDS
 	| KW_MILLISECONDS
 	| KW_BOOLEAN
 	| KW_INT
 	| KW_LONG
 	| KW_FLOAT
 	| KW_STRING
 	| KW_TIMESTAMP
 	| KW_DATE
 	| KW_TIME
 	| KW_DECIMAL
 	| KW_OPERATOR
 	| Identifier
 	;
 	
 streamProperties
    :	KW_PROPERTIES LPAREN streamPropertiesList RPAREN
    ;
    
confName
	:	StringLiteral
	;
	
/*
   配置属性的值只能是字符串类型，
   不支持其他类型
*/
confValue
	:	StringLiteral
	;

 
 columnName
 	: cqlIdentifier
 	;
 	
 className
	:   innerClassName
	|   userDefinedClassName
	;
 
 innerClassName
    :   cqlIdentifier
    ;
    
 userDefinedClassName
    :   StringLiteral
    ;
  
 streamName
 	:	cqlIdentifier
 	;

applicationName
	: cqlIdentifier
	| constIntegerValue
	;
	
path
	: StringLiteral
	;

isForce
	: KW_FORCE
    ;

columnALias
	:	cqlIdentifier
	;

identifierNot
	: KW_NOT
	;
	
nullCondition
	: identifierNot? KW_NULL
	;
	
streamNameOrAlias
	:	cqlIdentifier
	;
	
constNull
	:	KW_NULL
	;
 
/*
 *位操作符
 * 正、负等操作符号 
 */
unaryOperator
	:	PLUS 
	|	MINUS 
	|	TILDE
	;

functionName
	:	cqlIdentifier
	;
 
dataSourceName
    :	cqlIdentifier
    ;
    	
streamAlias
	:	cqlIdentifier
	;
    
 /*
  * lexer
  */
  
 //key words
 KW_CREATE 			:		'CREATE';
 KW_SHOW				: 		'SHOW';
 KW_EXPLAIN			: 		'EXPLAIN';
 KW_SET					:		'SET';
 KW_GET					:		'GET';
 KW_LOAD					:		'LOAD';
 KW_EXPORT				: 		'EXPORT';
 KW_DROP				:		'DROP';
 KW_ADD					:		'ADD';
 KW_SELECT				:		'SELECT';
 KW_COMMENT			:		'COMMENT';
 KW_FORCE				:		'FORCE';
 KW_SERDE				:		'SERDE';
 KW_WITH					:		'WITH';
 KW_PROPERTIES		: 		'PROPERTIES';
 KW_SOURCE			:		'SOURCE';
 KW_INPUT				:		'INPUT';
 KW_STREAM				: 		'STREAM';
 KW_OUTPUT				:		'OUTPUT';
 KW_SINK					:		'SINK';
 KW_SUBMIT				:		'SUBMIT';
 KW_APPLICATION		:		'APPLICATION';
 KW_DISTINCT			: 		'DISTINCT';
 KW_AND					: 		'AND';
 KW_OR					:		'OR';
 KW_BETWEEN			:		'BETWEEN';
 KW_IN						:		'IN';
 KW_LIKE					:		'LIKE';
 KW_RLIKE				:		'RLIKE';
 KW_REGEXP				:		'REGEXP';
 KW_CASE					:		'CASE';
 KW_WHEN				:		'WHEN';
 KW_THEN					:		'THEN';
 KW_ELSE					:		'ELSE';
 KW_END					:		'END';
 KW_CAST					:		'CAST';
 KW_EXISTS				:		'EXISTS';
 KW_IF						:		'IF';
 KW_FALSE				:		'FALSE';
 KW_AS						:		'AS';
 KW_NULL					:		'NULL';
 KW_IS					    :		'IS';
 KW_TRUE					:		'TRUE';
 KW_ALL					:		'ALL';
 KW_NOT					:		'NOT';
 KW_ASC					:		'ASC';
 KW_DESC					:		'DESC';
 KW_SORT					:		'SORT';
 KW_ORDER				:		'ORDER';
 KW_GROUP				:		'GROUP';
 KW_BY						:		'BY';
 KW_HAVING				:		'HAVING';
 KW_WHERE				: 		'WHERE';
 KW_FROM				:		'FROM';
 KW_ON					:		'ON';
 KW_JOIN					:		'JOIN';
 KW_PARALLEL			:		'PARALLEL';
 KW_FULL					:		'FULL';
KW_PRESERVE			:		'PRESERVE';
 KW_OUTER				:		'OUTER';
 KW_CROSS				:		'CROSS';
 KW_SEMI					:		'SEMI';
KW_LEFT					:		'LEFT';
KW_INNER				:		'INNER';
KW_NATURAL			:		'NATURAL';
KW_RIGHT				:		'RIGHT';
KW_INTO					:		'INTO';
KW_INSERT				:		'INSERT';
KW_OVERWRITE		:		'OVERWRITE';
KW_LIMIT					:		'LIMIT';
KW_UNION				:		'UNION';
KW_APPLICATIONS	:		'APPLICATIONS';
KW_WINDOWS			:		'WINDOWS';
KW_EXTENDED			:		'EXTENDED';
KW_FUNCTIONS		:		'FUNCTIONS';
KW_FILE					:		'FILE';
KW_INPATH				:		'INPATH';
KW_WINDOW			:		'WINDOW';
KW_JAR					:		'JAR';
KW_FUNCTION			:		'FUNCTION';
KW_COMBINE			:		'COMBINE';
KW_UNIDIRECTION	:		'UNIDIRECTION';
KW_TRIGGER			:		'TRIGGER';
KW_PARTITION			:		'PARTITION';
KW_SLIDE					:		'SLIDE';
KW_BATCH				:		'BATCH';
KW_RANGE				:		'RANGE';
KW_ROWS					:		'ROWS';
KW_TODAY				:		'TODAY';
KW_UNBOUNDED		:		'UNBOUNDED';
KW_EXCLUDE			:		'EXCLUDE';
KW_NOW					:		'NOW';
KW_PREVIOUS			:		'PREVIOUS';
KW_DATASOURCE		:		'DATASOURCE';
KW_SCHEMA				:		'SCHEMA';
KW_QUERY				:		'QUERY';
KW_DEACTIVE			:		'DEACTIVE';
KW_ACTIVE				:		'ACTIVE';
KW_WORKER				:		'WORKER';
KW_REBALANCE		:		'REBALANCE';
KW_OPERATOR         :   		'OPERATOR';
KW_USING                :   	'USING';
KW_DISTRIBUTE        :   	'DISTRIBUTE';
 
 /*
  *窗口时间单位 
  */
 KW_DAY					:		'DAY' | 'DAYS';
 KW_HOUR				:		'HOUR' | 'HOURS';
 KW_MINUTES			:		'MINUTE' | 'MINUTES';
 KW_SECONDS		:		'SECOND' | 'SECONDS';
 KW_MILLISECONDS	:		'MILLISECOND'|'MILLISECONDS';
 
 //DataTypes
KW_BOOLEAN			:		'BOOLEAN';
KW_INT						:		'INT';
KW_LONG					:		'LONG';
KW_FLOAT		 		:		'FLOAT';
KW_DOUBLE				:		'DOUBLE';
KW_STRING				:		'STRING';
KW_TIMESTAMP			:		'TIMESTAMP';
KW_DATE					:		'DATE';
KW_TIME					:		'TIME';
KW_DECIMAL			:		'DECIMAL';

// generated as a part of Number rule
DOT											:	'.';
COLON										:	':' ;
COMMA										:	',' ;
SEMICOLON								:	';' ;
LPAREN										:	'(' ;
RPAREN										:	')' ;
LSQUARE									:	'[' ;
RSQUARE									:	']' ;
LCURLY										:	'{';
RCURLY										:	'}';
EQUAL 										:	'=' | '==';
EQUAL_NS 								:	'<=>';
NOTEQUAL 								:	'<>' | '!=';
LESSTHANOREQUALTO 				:	'<=';
LESSTHAN 								:	'<';
GREATERTHANOREQUALTO			:	'>=';
GREATERTHAN							:	'>';
DIVIDE										:	'/';
PLUS											:	'+';
MINUS 										:	'-';
CONCATENATION 						:	'||';
STAR 										:	'*';
MOD 											:	'%';
DIV 											:	'DIV';
TILDE 										:	'~';
BITWISEOR 								:	'|';
AMPERSAND 								:	'&';
BITWISEXOR 							:	'^';
QUESTION 								:	'?';
DOLLAR 									:	'$';

 fragment
 Letter
 		: 'a'..'z' | 'A'..'Z'
 		;
 
 fragment 
 HexDigit
 			: 'a'..'f' | 'A' .. 'F'
 			;
 
 fragment
 Digit
 			: '0' .. '9'
 			;
 
fragment
Exponent
    :	('e' | 'E') ( PLUS|MINUS )? (Digit)+
    ;
    
 LongLiteral
    :	Number 'L'
    ;

FloatLiteral
    :	Number 'F'
    ;

DoubleLiteral
    :	Number 'D'
    ;

DecimalLiteral
    :	Number 'B' 'D'
    ;
/**
	Date、Time、TimeStamp类型比较特殊，不能使用常量，只能用udf函数的方式创建
	比如cast函数或者date函数
 */

StringLiteral
    :	( 
    		'\'' ( ~('\''|'\\') | ('\\' .) )* '\''
    		| '\"' ( ~('\"'|'\\') | ('\\' .) )* '\"'
    	)+
    ;

CharSetLiteral
    :	StringLiteral
    |	'0' 'X' (HexDigit|Digit)+
    ;

IntegerNumber
	:	(Digit)+
	;

Number
    :	(Digit)+ ( DOT (Digit)* (Exponent)? | Exponent)?
    ;

Identifier
    :	(Letter | Digit) (Letter | Digit | '_')*
    ;

CharSetName
    :	'_' (Letter | Digit | '_' | '-' | '.' | ':' )+
    ;

//
// Whitespace and comments
//
WS  
	:	[ \t\r\n\u000C]+ -> skip
    ;

COMMENT
    :	'/*' .*? '*/' -> skip
    ;

LINE_COMMENT
    :	  '--' ~[\r\n]* -> skip
    ;